#ifndef _DRETVE_H_
#define _DRETVE_H_

#include <vrijeme.h>
#include <jezgra/postavke.h>

//stanja drete
enum {
	AKTIVNA = 0,	//mora biti 0
	PRIPRAVNA = 1,	//mora biti 1

	/* dodaj ostala po potrebi */
	REDDRETVE,	//dretva ceka na zavrsetak druge dretve
	REDALARMA,	//dretva ceka na alarm
	REDUI,		//dretva ceka na dovrsetak UI operacije

	SEMAFOR,
	MONITOR,
	REDUVJETA,
	BARIJERA,
	CITAJPISI,

	DOGADJAJ,

	PASIVNA = NAJ_RED	//zavrsila je s radom
};

//uredjenje redova
#define SORT_PRP	1	//po redu prispijeca
#define SORT_PRIO	2	//prema prioritetu

//nacini rasporedjivanja (podrzan samo po redu prispijeca - FIFO)
#define RASP_PRP	1	//FIFO
#define RASP_KRUZNO	2	//RR
#define RASP_DRUGO	4	//nekako drukcije

//osnovno s dretvama
int stvori_dretvu_pr (void (*poc_funkc)(void *), void *param, void *stog,
			int prio, int rasp);
int stvori_dretvu (void (*poc_funkc)(void *), void *param);

int stvori_proces_pr ( void (*poc_funkc) (void *), void *param, void *stog,
			int prio, int rasp, bool priv, void *pocetna_adresa,
			uint velicina );
int stvori_proces ( void (*poc_funkc)(void *), void *param );
int zavrsi_proces ();
int prekini_proces ( int id_procesa );

int dretva_odstupi ();
int id_dretve ();
int zavrsi_dretvu ();

int dohvati_prioritet (int id);
int postavi_prioritet (int prio);

int cekaj_kraj_dretve (int id);


//sinkronizacija: semafor/monitor/red uvjeta

//semafor i monitor zastavice
#define REKURZ	0x10	//ne blokira u slucaju rekurzivnog poziva
#define NASPRIO	0x20	//nasljedivanje prioriteta
#define STROPNI	0x40	//nasljedivanje prioriteta (nije impl.)

//dodatne zastavice kod "cekaj" operacija
#define DRUGAOP	1
#define	PROBAJ	2

//dohvati novi sinkronizacijski objekt
int dohvati_sinkro (int tip, int sort, int zast, int pocvr);

//obrisi postojeci sinkronizacijski objekt
int obrisi_sinkro (int id);

//cekaj i postavi funkcije
int cekaj_sinkro (int red, uint zast, int mon, vrijeme_t *koliko);
int postavi_sinkro (int id, bool sve);


//semafor - koriste se gornje 'sinkro' funkcije
#define	cekaj_sem(sem)			cekaj_sinkro(sem, 0, -1, NULL)
#define	cekaj_sem_t(sem, koliko)	cekaj_sinkro(sem, 0, -1, koliko)
#define	probaj_cekati_sem(sem)		cekaj_sinkro(sem, PROBAJ, -1, NULL)

#define	postavi_sem(sem)		postavi_sinkro(sem, NEISTINA)


//monitor - koriste se gornje 'sinkro' funkcije
#define	zakljucaj(mon)			cekaj_sinkro(mon, 0, -1, NULL)
#define	zakljucaj_t(mon, koliko)	cekaj_sinkro(mon, 0, -1, koliko)
#define	probaj_zakljucati(mon)		cekaj_sinkro(mon, PROBAJ, -1, NULL)

#define	otkljucaj(mon)			postavi_sinkro(mon, NEISTINA)


//red uvjeta
#define	propusti_iz_reda(red)		postavi_sinkro(red, NEISTINA)
#define	propusti_sve_iz_reda(red)	postavi_sinkro(red, ISTINA)
#define	cekaj_u_redu(red, mon)		cekaj_sinkro(red, DRUGAOP, mon, NULL)
#define	cekaj_u_redu_t(red,mon,koliko)	cekaj_sinkro(red, DRUGAOP, mon, koliko)


//barijera
#define	dohvati_barijeru(n)		dohvati_sinkro(BARIJERA, SORT_PRIO,0,n)
#define	cekaj_na_barijeri(b)		cekaj_sinkro(b, 0, -1, NULL)
#define	cekaj_na_barijeri_t(b, koliko)	cekaj_sinkro(b, 0, -1, koliko)
#define	probaj_cekati_na_barijeri(b)	cekaj_sinkro(b, PROBAJ, -1, NULL)


//zakljucavanje citac/pisac
#define	CITAC	4
#define PISAC	8
#define	NITKO	0

#define	dohvati_pisi_citaj()		dohvati_sinkro(CITAJPISI, SORT_PRIO,0,0)

#define	zakljucaj_na_citanje(cpz)	   cekaj_sinkro(cpz, 0, CITAC, NULL)
#define	zakljucaj_na_citanje_t(cpz,koliko) cekaj_sinkro(cpz, 0, CITAC, koliko)
#define	probaj_zakljucati_na_citanje(cpz) cekaj_sinkro(cpz, PROBAJ, CITAC, NULL)

#define	zakljucaj_na_pisanje(cpz)	   cekaj_sinkro(cpz, 0, PISAC, NULL)
#define	zakljucaj_na_pisanje_t(cpz,koliko) cekaj_sinkro(cpz, 0, PISAC, koliko)
#define	probaj_zakljucati_na_pisanje(cpz) cekaj_sinkro(cpz, PROBAJ, PISAC, NULL)

#define	otkljucaj_citanje_pisanje(cpz)	postavi_sinkro(cpz, NEISTINA)


/* dio izbacen iz koda jezgre, jer se ne izvodi u jezgri */

//pocetna funkcija za sve dretve, iz argumenata se uzima funkcija koju je zadao
//korisnik te se ona poziva; kada dodje do kraja, dretva zavrsava
void pokreni_dretvu (void (*pocetna_funkcija)(void *), void *param);

void latentna_dretva (void *x);

#endif /* _DRETVE_H_ */
